#include "NotifyManager.h"
#include "UserManager.h"

extern UserManager user_manager;
NotificationManager::NotificationManager() {
    if(!fs::exists(NOTIFY_DIR)){
        fs::create_directories(NOTIFY_DIR);
    }
}

string NotificationManager::get_notify_file_path(int user_id) {
    return NOTIFY_DIR + to_string(user_id) + ".notify";
}

void NotificationManager::create_new_file(string file_path) {
    try{
    ofstream ofs;
    ofs.open(file_path, ios::out);
    NotifyQueue notify_queue;
    ofs << notify_queue.serialize().dump(4) << endl;
    ofs.close();
    }
    catch(exception&e){
        throw e;
    }
}

void NotificationManager::save_to_file(int user_id, const NotifyQueue_ptr& notify) {
    string file_path = get_notify_file_path(user_id);
    try{
        string temp_file_path = file_path + ".tmp"; // 创建临时文件路径
        ofstream ofs;

        ofs.open(temp_file_path, ios::out);
        ofs << notify->serialize().dump(4) << endl; // 写入数据到临时文件
        ofs.close(); // 关闭临时文件
        fs::rename(temp_file_path, file_path); // 替换原文件
    }
    catch(exception&e){
        throw e;
    }
}

void NotificationManager::load_from_file(int user_id, NotifyQueue_ptr& notify){
    try{
        string file_path = get_notify_file_path(user_id);
        if(!fs::exists(file_path)){
            create_new_file(file_path); 
            notify = make_unique<NotifyQueue>();
        }

        ifstream ifs;
        ifs.open(file_path, ios::in);
        json j;
        ifs >> j;
        notify = make_unique<NotifyQueue>(j);
        ifs.close();
    }
    catch(exception&e){
        throw e;
    }
}

void NotificationManager::save_all_notify(){
    try{
    for(auto& x:notify_queues){
        save_to_file(x.first, x.second);
    }
}
    catch(exception&e){
        throw e;
    }
}


NotifyQueue_ptr& NotificationManager::QuickLoadNotify(int user_id){
    if(notify_queues.find(user_id)==notify_queues.end()){
        try{
            load_from_file(user_id, notify_queues[user_id]);
        }
        catch(exception&e){
            throw e;
        }
    }
    return notify_queues[user_id];
}

void NotificationManager::add_notify(int user_id,  Notify_ptr notify){
    try{
        auto& notify_queue = QuickLoadNotify(user_id);
        notify_queue->add_notify(move(notify));
    }
    catch(exception&e){
        throw e;
    }
}

void NotificationManager::send_notify(int user_id, int socket_fd){
    try{
        auto& notify_queue = QuickLoadNotify(user_id);
        fs::remove(get_notify_file_path(user_id)); // 删除通知文件

        notify_queue->send_notify(socket_fd);
    }
    catch(exception&e){
        throw e;
    }
}

void NotificationManager::SaveNotifyToFile_regularly(int clear_frequency){
    while(true){
        try{
            std::this_thread::sleep_for(std::chrono::seconds(clear_frequency));
            lock_guard<mutex>lock(notify_queues_mutex);  
            save_all_notify();
            this->notify_queues.clear(); // 清空通知队列
            #ifdef DEBUG
                printf("NotificationManager::SaveNotifyToFile_regularly: clear notify_queues\n");
            #endif
        }
        catch(exception&e){
            throw e;
        }
    }
}

void NotificationManager::SendOrSaveNotify_regularly(int clear_frequency){
    while(true){
        try{
            std::this_thread::sleep_for(std::chrono::seconds(clear_frequency));
            lock_guard<mutex>lock(notify_queues_mutex);  
            for(auto& x:notify_queues)
            {
                if(user_manager.is_online(x.first)){
                    this->send_notify(x.first, user_manager.get_sockfd(x.first));
                    this->notify_queues.erase(x.first); // 删除通知队列
                }
            }
            save_all_notify();

            #ifdef DEBUG
                printf("NotificationManager::SendOrSaveNotify_regularly: 清理通知队列并发送通知\n");
            #endif
        }
        catch(exception&e){
            throw e;
        }
}}


NotificationManager* NotificationManager::instance = nullptr;

NotificationManager* NotificationManager::get_instance() {
    if(instance == nullptr){
        instance = new NotificationManager();
    }
    return instance;
}